/*
  Copyright (c) 2002, 2003 Russell Morris
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, 
  are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, 
      this list of conditions and the following disclaimer. 
      
    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution. 
      
    * The names of the contributors may not be used to endorse or promote 
      products derived from this software without specific prior written permission. 
      
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
    THE POSSIBILITY OF SUCH DAMAGE.
*/

namespace WRM.Windows.Forms.Design
{
  using System;
  using System.Windows.Forms;
  using System.Windows.Forms.Design;
  using System.ComponentModel;
  using System.ComponentModel.Design;
  using System.Collections;
  using System.Drawing;
  using System.Drawing.Drawing2D;

  /// <summary>
  /// The custom designer class for the the <see cref="PropertyPane">PropertyPane</see>
  /// class.
  /// </summary>
  /// <remarks>
  /// This designer class is <b>only</b> used for <see cref="PropertyPane">
  /// PropertyPane</see>, because it allows other controls to be dragged &amp;
  /// dropped onto it at design-time.  This action, of course, doesn't make
  /// sense for custom classes derived from <c>PropertyPane</c>.
  /// </remarks>
  public class PropertyPaneDesigner : ParentControlDesigner
  {
    /// <summary>
    ///   The <see cref="PropertyPane">PropertyPane</see> object we are designing.
    /// </summary>
    private PropertyPane mPropertyPane;

    /// <summary>
    ///   The pen we use to draw the border.
    /// </summary>
    private Pen mBorderPen;

    /// <summary>
    ///   Default constructor.
    /// </summary>
    public PropertyPaneDesigner() : base()
    {
      mBorderPen = new Pen(SystemBrushes.ControlDarkDark,1.5f); 
      mBorderPen.DashStyle = DashStyle.Dash;
    }
  
    /// <summary>
    /// Gets a value indicating how the designed component may be selected
    /// </summary>
    /// <value>
    /// Returns <see cref="SelectionRules.Visible">SelectionRules.Visible</see>
    /// </value>
    /// <remarks>
    /// Returns <see cref="SelectionRules.Visible">SelectionRules.Visible</see> only, 
    /// so that <see cref="PropertyPane"/> cannot be moved or resized during
    /// design-time.
    /// </remarks>
    public override SelectionRules SelectionRules
    {
      get
      {
        return SelectionRules.Visible | SelectionRules.Locked;
      }
    }



    /// <summary>
    /// Gets an <see cref="ICollection"/> containing all of the 
    /// <see cref="IComponent"/>s that are associated with this
    /// <see cref="PropertyPane"/>
    /// </summary>
    /// <value>
    ///   Return the list of components that depend upon this component.  In this
    /// case, this would be the list of components that have been added to the
    /// <see cref="PropertyPane"/> (like buttons, text boxes, etc...).
    /// </value>
    /// <remarks>
    /// This collection of associated components is used to determine dependancy
    /// relationships that must be honored by the design-time environment
    /// for certain operations (like Cut or Copy).
    /// </remarks>
    public override ICollection AssociatedComponents
    {
      get
      {
        return mPropertyPane.Controls;
      }      
    }
    
    /// <summary>
    ///   Initialize the designer with the <see cref="PropertyPane"/> it's designing.
    /// </summary>
    /// <param name="component">
    /// The <c>IComponent</c>-implementing object that is being attached to
    /// this designer.
    /// </param>
    /// <remarks>
    /// An exception is thrown if the supplied component is not a 
    /// <see cref="PropertyPane"/>-derived object.
    /// </remarks>
    /// <exception cref="ArgumentNullException">
    /// Thrown if <paramref name="component"/> is null
    /// </exception>
    /// <exception cref="ArgumentException">
    /// Thrown if <paramref name="component"/>does not descend from
    /// <see cref="PropertyPane"/>
    /// </exception>
    public override void Initialize(IComponent component) 
    {
      base.Initialize(component);
      
      if(component == null)
        throw new ArgumentNullException("component");
      
      if(!(component is PropertyPane))
        throw new ArgumentException(
          "PropertyPaneDesigner can only provide design-time services for " +
          "classes that descend from PropertyPane.  '" + component.GetType().FullName + "' " +
          "does not descend from PropertyPane.",
          "component");

      mPropertyPane = (PropertyPane)component;

      // Hook ExpandedChangedEvent so that we know when nodes are expanded and
      // collapsed (we need to persist this in code).
      // 
      //mPropertyPane.ExpandedChangedEvent += new PropertyPane.ExpandChangedEventHandler(this.OnExpandChanged);
    }

    /// <summary>
    /// Draw a border around the designed <see cref="PropertyPane"/> so that it's
    /// easy to distinguish between it and its container during design-time.
    /// </summary>
    /// <param name="pe">
    /// Paint event information
    /// </param>
    /// <remarks>
    /// I've never gotten this to work quite right - when positive width or height
    /// sizing takes place, nasty trails are left behind by the old borders that
    /// aren't drawn over.  Please feel free to take a shot at fixing it.
    /// </remarks>
    protected override void OnPaintAdornments(System.Windows.Forms.PaintEventArgs pe)
    {
      base.OnPaintAdornments(pe);

      // Draw a nice border around ourselves, so the user can see
      // where to put controls!  (If we didn't do this, it would
      // be hard to distinguish the PropertyPane surface from the
      // Form's surface).
      // 
      pe.Graphics.DrawRectangle(mBorderPen,
        1,1,mPropertyPane.Width-2,mPropertyPane.Height-2);
    }

    /// <summary>
    /// Fires the ExpandChanged event
    /// </summary>
    /// <param name="oldValue">The old value of the IsExpanded property</param>
    /// <param name="newValue">The new value of the IsExpanded property</param>
    internal void OnExpandChanged(bool oldValue, bool newValue)
    {
      RaiseComponentChanging(
        TypeDescriptor.GetProperties(typeof(PropertyPane))["IsExpanded"]);
      RaiseComponentChanged(
        TypeDescriptor.GetProperties(typeof(PropertyPane))["IsExpanded"],
        oldValue,
        newValue);
    }

    /// <summary>
    /// Filters out all properties that have to do with layout.
    /// </summary>
    /// <param name="properties">
    /// An <see cref="IDictionary">IDictionary</see> (key -> value pairs) that
    /// contains, as keys, the names of properties of the designed component.
    /// </param>
    /// <remarks>
    /// <para>
    /// We remove any properties having to do with sizing or positioning so that
    /// the user cannot set them at design-time.  This is because the 
    /// containing <see cref="PropertyTree"/> is solely responsible for the
    /// positioning of a <see cref="PropertyPane"/> and for its participation
    /// in tabbing.
    /// </para>
    /// <para>
    /// The following properties are removed:
    /// </para>
    /// <list type="bullet">
    /// <item><description>Anchor</description></item>
    /// <item><description>Dock</description></item>
    /// <item><description>DockPadding</description></item>
    /// <item><description>Enabled</description></item>
    /// <item><description>Location</description></item>
    /// <item><description>Size</description></item>
    /// <item><description>TabIndex</description></item>
    /// <item><description>TabStop</description></item>
    /// <item><description>Visible</description></item>
    /// </list>
    /// </remarks>
    protected override void PostFilterProperties(System.Collections.IDictionary properties)
    {
      base.PostFilterProperties(properties);

      string[] propsToRemove = {
                                 "Dock",
                                 "DockPadding",
                                 "Anchor",
                                 "TabIndex",
                                 "TabStop",
                                 "Visible",
                                 "Enabled",
                                 "Location",
                                 "Size"
                               };
      
      //Remove all properties that have to do with layout
      foreach(string prop in propsToRemove)
      {
        if(properties.Contains(prop))
          properties.Remove(prop);
      }
    }
  }
}
